<?php
/**
 * 树形结构
 * Created by PhpStorm.
 * User: 我想有个家
 * Date: 2019/1/9
 * Time: 9:09
 */

namespace App\Lib;


class Tree {

    protected static $config = array(
        /* 主键 */
        'primary_key' => 'id',
        /* 父键 */
        'parent_key' => 'parent_id',
        /* 父名称 */
        'parent_name' => 'parent_path',
        /* 父名名称键名 */
        'parent_name_key' => 'path',
        /* 孩子节点属性 */
        'children_key' => 'children',
        /* 是否展开子节点 */
        'expanded' => true
    );

    /* 结果集 */
    protected static $result = array();

    /* 层次暂存 */
    protected static $level = array();

    /**
     * 生成树形结构
     * @param $data
     * @param array $options
     * @return array
     */
    public static function makeTree($data, $options = array()) {
        $dataset = self::buildData($data, $options);
        return self::makeTreeCore(0, $dataset, '', 'normal');
    }

    /* 生成线性结构, 便于HTML输出, 参数同上 */
    public static function makeTreeForHtml($data, $options = array()) {

        $dataset = self::buildData($data, $options);
        return self::makeTreeCore(0, $dataset, '', 'linear');
    }

    /* 格式化数据, 私有方法 */
    private static function buildData($data, $options) {
        $config = array_merge(self::$config, $options);
        self::$config = $config;

        $r = array();
        foreach ($data as $item) {
            $id = $item[$config['primary_key']];
            $parent_id = $item[$config['parent_key']];
            $r[$parent_id][$id] = $item;
        }

        return $r;
    }

    /* 生成树核心, 私有方法  */
    private static function makeTreeCore($index, $data, $parentName, $type = 'linear') {
        $config = self::$config;
        $r = [];
        foreach ($data[$index] as $id => $item) {
            $item[$config['parent_name']] = $parentName;
            if ($type == 'normal') {
                if (isset($data[$id])) {
                    $item[$config['children_key']] = self::makeTreeCore($id, $data, $item[$config['parent_name_key']], $type);
                } else {
                    $item[$config['children_key']] = [];
                }
                $r[] = $item;
            } else {
                self::$result[] = $item;
                if (isset($data[$id])) {
                    self::makeTreeCore($id, $data, $item[$config['parent_name_key']], $type);
                }
                $r = self::$result;
            }
        }
        return $r;
    }

    public static function mTree($arr, $start = 0, $options = []) {
        $l = [];
        $config = array_merge(self::$config, $options);
        self::tree($arr, $l, $start, $config['primary_key'], $config['parent_key']);
        return $l;
    }

    /**
     * @param $arr array
     * @param $l array
     * @param int $p
     * @param $key string
     * @param $parent string
     */
    public static function tree($arr, &$l, $p, $key, $parent) {
        foreach ($arr as $a) {
            if ($a[$parent] == $p) {
                $l[] = $a;
                self::tree($arr, $l, $a[$key], $key, $parent);
            }
        }
    }
}

